/**
 *
 */
package org.cmcc.pcap.packet.tcp;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.cmcc.pcap.packet.capture.HandlerManager;

import java.util.ArrayList;
import java.util.HashMap;

/**
 * @Date 2018年1月16日 下午7:45:07
 * @author Amish
 *
 */
public class TcpProtocolDispatcher implements Runnable {
    private static Logger logger = LogManager.getLogger(TcpProtocolDispatcher.class);
    boolean flag = true;//忘了干啥用的了....

    TcpConnectionCache tcpConnectionCache;

    private HashMap<String, TcpProtocolHandler> hashmap;
    private String taskId;

    public String getTaskId() {
        return taskId;
    }

    public void setTaskId(String taskId) {
        this.taskId = taskId;
    }

    public TcpProtocolDispatcher(TcpConnectionCache tcpConnectionCache) {
        this.tcpConnectionCache = tcpConnectionCache;
        this.hashmap = new HashMap<>();
    }

    /**
     * 用于识别TCP的应用层协议，并返回对应的Handler
     * @return
     */
    private TcpProtocolHandler distinguishTcpProtocol(TcpConnection tcpConnection) {
        //根据TcpProtocolFilter的结果，直接判断TcpConnection中的对应成员变量
        switch (tcpConnection.protocol) {
            case HTTP: {
                if (hashmap.containsKey("HTTP")) {
                    return hashmap.get("HTTP");
                } else {
                    try {
                        hashmap.put("HTTP", HandlerManager.getHandler("http"));
                    } catch (IllegalAccessException | InstantiationException e) {
                        logger.error("new httpHandler exception:" + e);
                    }
                    return hashmap.get("HTTP");
                }
//    	    return new HttpHandler();
            }


            case HTTPS: {
                if (hashmap.containsKey("HTTPS")) {
                    return hashmap.get("HTTPS");
                } else {
                    try {
                        hashmap.put("HTTPS", HandlerManager.getHandler("https"));
                    } catch (IllegalAccessException | InstantiationException e) {
                        logger.error("new tcpHandler exception:" + e);
                    }
                    return hashmap.get("HTTPS");
                }
            }

            case TCP: {
                logger.debug("this is return tcp handler !");
                if (hashmap.containsKey("TCP")) {
                    return hashmap.get("TCP");
                } else {
                    try {
                        hashmap.put("TCP", HandlerManager.getHandler("tcp"));
                    } catch (IllegalAccessException | InstantiationException e) {
                        logger.error("new tcpHandler exception:" + e);
                    }
                    return hashmap.get("TCP");
                }
            }

            default:
                //return new DefaultProtocolHandler();
                logger.info("Can not dispatcher protocol : " + tcpConnection.protocol.name() + " with first seq num : " + tcpConnection.al.get(0).tcpPacket.getHeader().getSequenceNumberAsLong());
                return null;
        }
    }

    @Override
    public void run() {
        while (this.flag) {
            ArrayList<TcpConnection> al = tcpConnectionCache.getTcpConnection();//此处由于同步 可能阻塞
            //int totalHandledPacketNum = 0;
            for (TcpConnection tcpConnection : al) {
                int handledPacketNum = tcpConnection.al.size();//提前获取需要处理的Packet数量，TOFIX何时清零的？
                try {
                    TcpProtocolHandler tcpProtocolHandler = distinguishTcpProtocol(tcpConnection);
                    if (tcpProtocolHandler != null) {
                        //	logger.debug("start execute tcp protocol handler !");
                        tcpProtocolHandler.handle(tcpConnection,taskId);
                    } else {
                        //logger.error("Can not the protocol handler");
                    }
                } catch (Exception e) {
                    logger.error(e.getCause(), e);
                } finally {
                    //totalHandledPacketNum += handledPacketNum;
                    tcpConnectionCache.handledPacketNum.getAndAdd(handledPacketNum);//记录已经处理的Packet数量
                }

            }
            //TODO TOFIX lvpin 20180619 如果写库操作放在这里，应该在写库操作完成后，使用totalHandledPacketNum来计数，否则可能导致提前结束处理

        }
    }

    public void terminate() {
        this.flag = false;
    }


}
